package com.suppor.rpc.client.proxy;

import com.suppor.rpc.client.ClientSend;
import com.suppor.rpc.core.trans.RpcRequest;
import com.suppor.rpc.core.trans.RpcResponse;
import com.suppor.rpc.core.util.RpcFuture;
import com.suppor.rpc.core.util.RpcServiceUtil;
import com.suppor.rpc.proto.protocol.MsgHeader;
import com.suppor.rpc.proto.protocol.MsgStatus;
import com.suppor.rpc.proto.protocol.MsgType;
import com.suppor.rpc.proto.protocol.RpcProtocol;
import com.suppor.rpc.proto.serialization.SerializationTypeEnum;
import com.suppor.rpc.register.RegisterService;
import io.netty.channel.DefaultEventLoop;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

public class ClientInvocationHandler implements InvocationHandler {
    private String serviceVersion;
    private int timeOut;
    private RegisterService registerService;

    public ClientInvocationHandler(String serviceVersion, int timeOut, RegisterService registerService) {
        this.serviceVersion = serviceVersion;
        this.timeOut = timeOut;
        this.registerService = registerService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Long requestId = RpcServiceUtil.REQUEST_ID_GENERATE.getAndIncrement();
        // 代理客户端的远程访问
        RpcProtocol<RpcRequest> protocol = new RpcProtocol<>();
        // head
        MsgHeader header = new MsgHeader();
        header.setMagic(MsgHeader.MAGIC_NUMBER);
        header.setVersion(MsgHeader.PROTOCOL_VERSION);
        header.setStatus(MsgStatus.SUCCESS.getCode().byteValue());
        header.setMsgType(MsgType.REQUEST.getType().byteValue());
        header.setSerializeType(SerializationTypeEnum.HESSIAN.getType().byteValue());
        header.setRequestId(requestId);

        protocol.setHeader(header);

        // request
        RpcRequest request = new RpcRequest();
        request.setMethodName(method.getName());
        request.setServiceImpl(method.getDeclaringClass().getName());
        request.setParameterTypes(method.getParameterTypes());
        request.setParas(args);
        request.setServiceVersion(this.serviceVersion);
        protocol.setBody(request);

        // 发送请求
        ClientSend send = new ClientSend();
        RpcFuture<RpcResponse> future = new RpcFuture<>(new DefaultPromise<>(new DefaultEventLoop()), this.timeOut);
        // 本地记录请求和响应的future
        RpcServiceUtil.responseFuture.put(requestId, future);
        // 发送到远端
        send.send(protocol, this.registerService);
        // 最后获得结果
        Promise<RpcResponse> promise = future.getPromise();
        RpcResponse result =  promise.get(future.getTimeOut(), TimeUnit.MILLISECONDS);
        return result.getResponse();
    }
}
